import drawUtils from "./drawUtils";
import jsPDF from "jspdf";
import imgs from "./imgs";

const img = imgs.deleteImg
const settingImg = imgs.settingImg

const createSetting = function (mouseUpHandler) {
  return new fabric.Control({
    x: 0,
    y: 0,
    offsetY: 0,
    cursorStyle: 'pointer',
    mouseUpHandler: (eventData, transform) => {
      mouseUpHandler(eventData, transform)
    },
    render: (ctx, left, top, styleOverride, fabricObject) => {
      const size = 20;
      ctx.save();
      ctx.translate(left, top);
      ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
      ctx.drawImage(settingImg, -size / 2, -size / 2, size, size);
      ctx.restore();
    },
    cornerSize: 20
  })
};

class Content {

  //内容列表
  contentList = []
  //可以填充的区域
  contentRect = null

  //全部元素
  allCanvasItems = []

  debugger = false
  //页面
  page = null

  contentW = 0

  contentH = 0

  constructor(page) {
    this.page = page
    this.contentW = this.page.contentRect[2]
    this.contentH = this.page.contentRect[3]
    if (false) {
      this.page.sheet.canvas.add(
        new fabric.Rect({
          left: this.createContentX(0),
          top: this.createContentY(0),
          width: this.contentW,
          height: this.contentH,
          stroke: 'black',
          lockMovementX: true,
          lockMovementY: true,
          hasControls: false,
          selectable: true,
          fill: 'transparent'
        })
      );
    }
  }

  clear() {
    this.contentList.forEach(item => {
      item.canvasItems.forEach(i => {
        this.page.sheet.canvas.remove(i)
      });
    })
  }
  removeAndNextALl(data) {
    const newList = []
    const removeList = this.contentList.filter((item, index) => {
      let b = index >= data.index;
      if (!b) {
        newList.push(item)
      }
      return b;
    });
    removeList.forEach(remove => {
      remove.canvasItems.forEach(item => {
        this.page.sheet.canvas.remove(item)
      })
    })

    this.contentList = newList
  }

  getFreeHeight() {
    this.lastContent = this.contentList.length > 0 ? this.contentList[this.contentList.length - 1] : null;
    if (!this.lastContent) {
      return this.contentH
    }
    let lastRect = this.lastContent.relativeContentRect
    return this.contentH - lastRect[1] - lastRect[3];
  }
  addLast(data, canvasItems) {

    if (data.data.debugger1) {
      debugger
    }

    this.lastContent = this.contentList.length > 0 ? this.contentList[this.contentList.length - 1] : null;
    let positions = []

    canvasItems.forEach(item => {
      // this.allCanvasItems.push(item)
      positions.push([
        item.left, item.top, item.width, item.height
      ])
    })

    let rect = drawUtils.getRect(positions)
    let relativeContentRect = []
    if (this.lastContent == null) {
      relativeContentRect = [0, 0, rect[2] + rect[0], rect[3] + rect[1]];
    } else {
      let lastRect = this.lastContent.relativeContentRect;
      const freeContentW = this.contentW - lastRect[0] - lastRect[2]
      let freeContentH = this.contentH - lastRect[1] - lastRect[3]
      let eqRow = false
      if (freeContentW > rect[2] + rect[0]) {
        freeContentH = freeContentH + lastRect[2]
        eqRow = true
      }
      if (freeContentH >= rect[3] + rect[1]) {
        if (eqRow) {
          relativeContentRect = [
            lastRect[0] + lastRect[2],
            lastRect[1], rect[2] + rect[0], Math.max(rect[3], lastRect[3])]
        } else {
          relativeContentRect = [0, lastRect[1] + lastRect[3], rect[2] + rect[0], rect[3] + rect[1]]
        }
      } else {
        return false
      }

    }
    if (relativeContentRect.length <= 0) {
      return false;
    }

    let absoluteContentRect = [
      this.createContentX(relativeContentRect[0]),
      this.createContentY(relativeContentRect[1]),
      relativeContentRect[2],
      relativeContentRect[3],
    ];

    let items = {
      data: data,
      index: this.contentList.length,
      canvasItems: canvasItems.map(item => {
        item.left = absoluteContentRect[0] + item.left
        item.top = absoluteContentRect[1] + item.top
        return item
      }),
      relativeContentRect: relativeContentRect,
      absoluteContentRect: absoluteContentRect,
    };
    data.data.getPositions = () => {
      return absoluteContentRect
    }
    data.data.items = items
    this.lastContent = items

    this.contentList.push(items);
    this.lastContent.canvasItems.forEach(i => {
      this.page.sheet.canvas.add(i)
    })
    if (this.debugger) {
      this.page.sheet.canvas.add(
        new fabric.Textbox(items.index + '', {
          left: absoluteContentRect[0],
          top: absoluteContentRect[1],
          width: absoluteContentRect[2],
          height: absoluteContentRect[3],
          stroke: 'black',
          fontSize: 10,
          lockMovementX: true,
          lockMovementY: true,
          hasControls: false,
          selectable: true,
        }),
        new fabric.Rect({
          left: absoluteContentRect[0],
          top: absoluteContentRect[1],
          width: absoluteContentRect[2],
          height: absoluteContentRect[3],
          stroke: 'black',
          lockMovementX: false,
          lockMovementY: false,
          hasControls: false,
          selectable: true,
          fill: 'transparent'
        })
      );
    }

    return true;
  }

  addFirst(data, canvasItems) {

  }

  createContentX(x) {
    return this.page.contentRect[0] + x;
  }

  createContentY(y) {
    return this.page.contentRect[1] + y
  }
}

class Page {

  margin = []//外

  pageText = null

  pointer = []//定位点

  page = 0

  contentManager = null

  questions = []

  codes = []

  contentRect = null;

  contentW

  contentH


  constructor(canvas, rect, page, sheet) {
    this.canvas = canvas
    this.rect = rect
    this.x = rect[0]
    this.y = rect[1]
    this.width = rect[2]
    this.height = rect[3]
    this.page = page
    this.sheet = sheet
    this.contentRect = [
      this.createX(this.sheet.margin[3]),
      this.createY(this.sheet.margin[0]),
      this.sheet.pageW - this.sheet.margin[1] - this.sheet.margin[3],
      this.sheet.pageH - this.sheet.margin[0] - this.sheet.margin[2],
    ]
    this.contentW = this.contentRect[2]
    this.contentH = this.contentRect[3]
    this.contentManager = new Content(this)
    this.createMargin(this.sheet.margin)
  }

  getFreeHeight() {
    return this.contentManager.getFreeHeight()
  }

  clear() {
    this.contentManager.clear();
    this.clearPageText()
    this.clearMargin()
  }
  createQuestions(questions) {
    //
    const f = this.sheet.appendQuestion
    const data = {
      callback: f,
      questions: questions,
      params: function () {
        return [questions[0]]
      },
      questionFuns: [],
      type: "questions",

    }
    const groupMaxNumber = 5
    const ttw = 20
    const tth = 10
    const tts = 6
    const marginLeft = 16
    const marginTop = 20
    const textWidth = 20
    const fontSize = textWidth * 0.8

    const canvas = []
    const groups = []
    const length = questions.length
    const questionFun = []
    for (let i = 0; i < length; i++) {
      data.questions[i].positions = []
      const allPositions = []

      let group = groups[groups.length - 1];
      if (!group) {
        group = []
        groups.push(group)
      }
      if (group.length === groupMaxNumber) {
        group = [];
        groups.push(group);
      }
      const groupItem = {}
      groupItem.canvasList = []
      group.push(groupItem)
      let question = questions[i];
      const {
        questionId,
        questionIndex,
        selectNumber,
        baseType,
        paperIndex
      } = question
      let textbox = new fabric.Textbox(paperIndex, {
        left: marginLeft,
        top: marginTop,
        width: textWidth,
        height: fontSize,
        fontSize: fontSize,
        textAlign: 'left',
        verticalAlign: 'middle',
        hasControls: false,
        selectable: false,
      });
      canvas.push(textbox)
      groupItem.canvasList.push(textbox)

      allPositions.push([textbox.left, textbox.top, textbox.width, textbox.fontSize])

      for (let j = 0; j < selectNumber; j++) {

        let rect = new fabric.Rect({
          left: marginLeft + 4 + ((ttw + tts) * j) + textWidth,
          top: marginTop + (fontSize / 2) - (tth / 2) + 1,
          width: ttw,
          height: tth,
          stroke: 'black',
          lockMovementX: true,
          lockMovementY: true,
          hasControls: false,
          selectable: false,
          fill: 'transparent'
        });
        const textSelect = ["v", "x"]
        let text = new fabric.Textbox(baseType === 'pd' ? textSelect[j] : String.fromCharCode(65 + j), {
          left: rect.left,
          top: rect.top - (fontSize * 0.1),
          width: rect.width,
          fontSize: fontSize * 0.7,
          textAlign: 'center',
          verticalAlign: 'middle',
          hasControls: false,
          selectable: false,
        });
        canvas.push(rect)
        canvas.push(text)

        data.questions[i].positions.push({
          position: () => {
            return [rect.left, rect.top, rect.width, rect.height]
          },
          value: text.text
        })
        allPositions.push([rect.left, rect.top, rect.width, rect.height])
      }
      groupItem.rect = drawUtils.getRect(allPositions)

    }
    return this.contentManager.addLast(
      {
        data: data
      },
      canvas
    );
  }
  createKb(question, totalH, control) {
    const _this = this
    const marginLeft = 0
    const marginTop = 10
    const textWidth = 20
    const fontSize = textWidth * 0.8
    const data = {
      question: question,
      isSubjective: true,
      type: 'subjective',
      callback: totalH != null ? this.sheet.appendKb : () => {},
      params: function () {
        return[{...question, height: totalH}, totalH != null]
      }
    }
    const {
      questionId,
      questionIndex,
      baseType,
      paperIndex,
      height
    } = question

    const edit = new fabric.Textbox(paperIndex, {
      left: marginLeft,
      top: marginTop,
      width: 30,
      fontSize: fontSize,
      lockMovementX: true,
      lockMovementY: true,
      selectable: false,
      hasControls: false,
    })
    const rect = new fabric.Rect({
      left: marginLeft,
      top: marginTop,
      width: this.contentW,
      height: height - marginTop,
      fill: 'transparent',
      stroke: "black",
      lockMovementX: true,
      lockMovementY: true,
      selectable: true,
      hasControls: true,
    })
    if (control) {

      const changeCallback = (newHeight) => {

        let allContent = _this.sheet.allContent();
        let message = data.items.data.data.question;
        message.height = newHeight

        let questionRects = allContent.filter(item => {
          try {
            if (item.item.data.data.type !== "subjective") {
              return false
            }
            let data1 = item.item.data.data.question;
            return (data1.questionId === message.questionId
              && message.questionIndex === data1.questionIndex)
          } catch (e) {
            return false;
          }

        });
        if (questionRects.length > 0) {
          let params = questionRects[0].item.data.data.params();
          let height1 = questionRects.map(item => item.item.data.data.question.height).reduce((n1, n2) => n1 + n2, 0);
          params[0].height = Math.max(height1 - 3, 50)
          params[0].sourceHeight = height1
          questionRects[0].item.data.data.params = () => {
            return params
          }
          _this.sheet.reRender(questionRects[0].page, questionRects[0].item.data.data, false)

        }
      }
      rect.controls = {
        mb: rect.controls.mb,
        deleteControl: new fabric.Control({
          x: 0.5,
          y: -0.5,
          offsetY: 0,
          cursorStyle: 'pointer',
          mouseUpHandler: (eventData, transform) => {
            changeCallback(0)
          },
          changeCallback: changeCallback,
          render: (ctx, left, top, styleOverride, fabricObject) => {
            var size = 20;
            ctx.save();
            ctx.translate(left, top);
            ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
            ctx.drawImage(img, -size / 2, -size / 2, size, size);
            ctx.restore();
          },
          cornerSize: 20
        })
      }


    } else {
      rect.controls = {}
    }

    // data.getPositions = () => {
    //   return [rect.left, rect.top, rect.width, rect.height]
    // }
    let addLast = this.contentManager.addLast(
      {
        data: data
      },
      [rect, edit]
    );
    if (control) {
      const sourceTop = rect.top
      rect.on('modified', function (e) {
        if (parseInt(sourceTop) !== parseInt(e.target.top)) {
          rect.controls.deleteControl.changeCallback(0)
          return
        }
        let newHeight = e.target.getScaledHeight();
        if (newHeight < 40) {
          rect.controls.deleteControl.changeCallback(0)
          return
        }
        rect.controls.deleteControl.changeCallback(newHeight)
      });
    }

    return addLast
  }

  createTk(question) {
    const marginLeft = 0
    const marginTop = 30
    const textWidth = 20
    const fontSize = textWidth * 0.8
    const inputSplitWidth = 10
    const positions = []
    let data = {
      type: 'tk',
      isSubjective: true,
      question: question,
      isQuestion: true,

      callback: this.sheet.appendTkSubjective,
      params: function () {
        return [question]
      }
    };
    const {
      questionId,
      questionIndex,
      inputWidth,
      inputNumber,
      paperIndex,
      lineHeight
    } = question

    const text = new fabric.Textbox(paperIndex, {
      left: marginLeft,
      top: marginTop,
      width: textWidth,
      fontSize: fontSize,
      textAlign: 'left',
      verticalAlign: 'middle',
      lockMovementX: true,
      lockMovementY: true,
      selectable: false,
      hasControls: false,
    })

    positions.push([marginLeft, marginTop, textWidth, text.height])

    const lines = []
    const maxInputWidth = this.contentW - textWidth - 10

    const maxLineNumber = parseInt(maxInputWidth / (inputWidth + inputSplitWidth))
    for (let i = 0; i < inputNumber; i++) {
      let other = i % maxLineNumber
      const lineNo = parseInt(i / maxLineNumber)

      lines.push(
        new fabric.Rect({
          left: marginLeft + 4 + (lineNo > 0 ? 0 : textWidth) + (other * (inputWidth + inputSplitWidth)),
          top: marginTop + fontSize + (lineNo * lineHeight) + 6,
          width: inputWidth,
          height: 1,
          // verticalAlign: 'middle',
          lockMovementX: true,
          lockMovementY: true,
          selectable: false,
          hasControls: false,
        })
      )
    }
    lines.forEach(line => {
      positions.push([line.left, line.top, line.width, line.height])
    })
    let rect = drawUtils.getRect(positions);
    const setting = new fabric.Rect({
      left: rect[0],
      top: rect[1],
      width: rect[2],
      height: rect[3],
      // verticalAlign: 'middle',
      lockMovementX: true,
      lockMovementY: true,
      selectable: true,
      fill: 'transparent',
      hasControls: true,
      controls: {
        setting: createSetting(
          () => {
            if (this.sheet.config.settingQuestion) {
              this.sheet.config.settingQuestion(this, data);
            }

          }
        )
      }
    })
    // data.getPositions = () => {
    //   return [setting.left, setting.top, setting.width, setting.height]
    // }
    return this.contentManager.addLast({
      data: data
    }, [text, ...lines, setting]);



  }

  createHeadTitle() {
    if (this.sheet.config.title) {
      this.contentManager.addLast({
          data: {
            type: "title"
          }
        },
        [
          new fabric.Textbox(this.sheet.config.title, {
            left: 0,
            top: 10,
            width: this.contentW,
            fontSize: 30,
            height: 30,
            textAlign: 'center',
            verticalAlign: 'middle',

            lockMovementX: true,
            lockMovementY: true,
            selectable: false,
            hasControls: false,
          })
        ]
      )
    }
  }

  createContentTitle(title) {
    const _this = this
    let f = this.sheet.appendContentTitle;
    const data = {
      callback: f,
      params: function () {
        return [canvasItems[0].text]
      },
      type: "contentTitle"
    };
    let canvasItems = [
      new fabric.Textbox(title, {
        left: 0,
        top: 20,
        width: this.contentW,
        height: 23,
        textAlign: 'left',
        verticalAlign: 'middle',
        fill: 'black',
        fontSize: 20,
        lockMovementX: true,
        lockMovementY: true,
        selectable: true,
        hasControls: true,
        controls: {
          deleteControl: new fabric.Control({
            x: 0.5,
            y: -0.5,
            offsetY: 0,
            cursorStyle: 'pointer',
            mouseUpHandler: (eventData, transform) => {
              this.sheet.removeContent(_this, data)
            },
            render: (ctx, left, top, styleOverride, fabricObject) => {
              var size = 20;
              ctx.save();
              ctx.translate(left, top);
              ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
              ctx.drawImage(img, -size / 2, -size / 2, size, size);
              ctx.restore();
            },
            cornerSize: 20
          })
        }
      })
    ];

    return this.contentManager.addLast({
      data: data
    }, canvasItems);
  }

  createCodeContent()  {
    if (this.sheet.config.code && this.sheet.config.code.number > 0) {
      const inputW = 26
      const codeW = 26 * this.sheet.config.code.number
      const codeH = 185
      const titleHeadH = 20;
      const inputH = 20
      let inputRects = []
      const leftMagin = 50
      const marginTop = 20
      const ttW = 20
      const tth = 10
      const tts = 4
      const ttn = 10
      const ttList = []

      const texts = []
      this.codes = []
      for (let i = 0; i < this.sheet.config.code.number; i++) {

        const rectList = []
        for (let j = 0; j < ttn; j++) {
          texts.push(new fabric.Textbox("" + j, {
            left: leftMagin + (i * inputW) + 4,
            top: titleHeadH + marginTop + 3 + ((tts + tth) * j) + inputH,
            width: ttW,
            height: tth,
            // stroke: 'black',
            fontSize: ttW * 0.6,
            textAlign: 'center',
            lockMovementX: true,
            lockMovementY: true,
            selectable: false,
            hasControls: false,
          }))
          let rect = new fabric.Rect({
            left: leftMagin + (i * inputW) + 4,
            top: titleHeadH + marginTop + 5 + ((tts + tth) * j) + inputH,
            width: ttW,
            height: tth,
            fill: 'transparent',
            stroke: 'black',
            strokeWidth: 1,
            lockMovementX: true,
            lockMovementY: true,
            selectable: false,
            hasControls: false,
          });
          ttList.push(rect)
          rectList.push(rect)
        }
        this.codes.push(() => {
          const positions = rectList.map(item => {
            return [item.left, item.top, item.width, item.height]
          })
          return {
            container: drawUtils.getRect(positions),
            positions: positions.map((item, index) => {
              return {
                value: index + "",
                position: item

              }
            })
          }
        })
        inputRects.push(new fabric.Rect({
          left: leftMagin + (i * inputW),
          top: titleHeadH + marginTop,
          width: inputW,
          height: inputH,
          fill: 'transparent',
          stroke: 'black',
          strokeWidth: 1,
          lockMovementX: true,
          lockMovementY: true,
          selectable: false,
          hasControls: false,
        }))
      }
      this.contentManager.addLast({
          data: {
            type: "code"
          },
        },
        [
          ...texts,
          ...ttList,
          ...inputRects,
          new fabric.Rect({
            left: leftMagin,
            top: marginTop,
            width: codeW,
            height: inputH,
            fill: 'transparent',
            stroke: 'black',
            strokeWidth: 1,
            lockMovementX: true,
            lockMovementY: true,
            selectable: false,
            hasControls: false,

          }),
          new fabric.Textbox("准考证号", {
            left: leftMagin,
            top: marginTop + 2,
            width: codeW,
            height: inputH,
            textAlign: 'center',
            fill: 'black',
            // stroke: 'black',
            fontSize: inputH * 0.7,
            // strokeWidth: 1,
            lockMovementX: true,
            lockMovementY: true,
            selectable: false,
            hasControls: false,

          }),
          new fabric.Rect({
            left: leftMagin,
            top: marginTop,
            width: codeW,
            height: codeH,
            fill: 'transparent',
            stroke: 'black',
            strokeWidth: 1,
            lockMovementX: true,
            lockMovementY: true,
            selectable: false,
            hasControls: false,

          })
        ]
      )
    }
  }

  createTipContent() {
    if (this.sheet.config.showTip) {
      const l = 25
      this.contentManager.addLast({
          data: {
            type: "tip"
          }
        },
        [
          new fabric.Textbox(
            `注意事项：
1.答题前请将姓名、班级、学校、准考证号填写清楚。
2.考生不得填涂缺考。
3.保持答题卡清洁平整，不可折叠。
4.请在题目区域内完成作答。`, {
              left: 10 + l,
              top: 24,
              width: 250,
              height: 185,
              fontSize: 13,
              textAlign: 'left',
              splitByGrapheme: true,
              lockMovementX: true,
              lockMovementY: true,
              selectable: false,
              hasControls: false,
            }),
          new fabric.Rect({
            left: 0 + l,
            top: 20,
            width: 260,
            height: 185,
            fill: 'transparent',
            stroke: 'black',
            strokeWidth: 1,
            lockMovementX: true,
            lockMovementY: true,
            selectable: false,
            hasControls: false,

          })
        ]
      )
    }
  }

  createInputRect() {
    let inputs = this.sheet.config.inputs;
    if (inputs.length > 0) {
      inputs.forEach(input => {

        this.contentManager.addLast({
            data: {
              type: "input"
            }
          },
          [
            new fabric.Textbox(input, {
              left: 0,
              top: 20,
              width: 150,
              fontSize: 18,
              height: 18,
              textAlign: 'left',
              lockMovementX: true,
              lockMovementY: true,
              selectable: false,
              hasControls: false,
            }),
            new fabric.Rect({
              left: 18 * 2 + 10,
              top: 20 + 18,
              width: 100,
              height: 1,
              fill: 'black',
              lockMovementX: true,
              lockMovementY: true,
              selectable: false,
              hasControls: false,
              // stroke: 'black',
              // strokeWidth: 1
            })
          ]
        )
      })
      this.contentManager.addLast({
        data: {
          type: 'none'
        }
      }, [
        new fabric.Rect({
          left: 0,
          top: 0,
          width: this.contentW,
          height: 1,
          fill: 'transparent',
          lockMovementX: true,
          lockMovementY: true,
          selectable: false,
          hasControls: false,

        })
      ])
    }
  }

  clearPageText() {
    if (this.pageText != null) {

      this.canvas.remove(this.pageText)
      return
    }
  }
  createPageText() {
    this.clearPageText()

    let botRect = this.margin[2];
    this.pageText = new fabric.Textbox(`第${this.page}页,共${this.sheet.pages.length}页`, {
      left: botRect.left,
      top: botRect.top + 30,
      width: botRect.width,
      fontSize: botRect.height * 0.23,
      textAlign: 'center',
      hasControls: false,
      selectable: false,
    })
    this.canvas.add(this.pageText)
  }

  clearMargin() {
    this.margin.forEach(item => {
      this.canvas.remove(item)
    })
    this.pointer.forEach(item => {
      this.canvas.remove(item)
    })
  }
  createMargin(margins) {

    //top
    const topMargin = new fabric.Rect({
      left: this.createX(0),
      top: this.createY(0),
      width: this.width,
      height: margins[0],
      lockMovementX: true,
      lockMovementY: true,
      selectable: false,
      hasControls: false,
    })
    this.margin.push(topMargin)
    //right
    const rightMargin = new fabric.Rect({
      left: this.createX(this.width - margins[1]),
      top: this.createY(0),
      width: margins[1],
      height: this.height,
      lockMovementX: true,
      lockMovementY: true,
      selectable: false,
      hasControls: false,
    })
    this.margin.push(rightMargin)
    //bottom
    const bottomMargin = new fabric.Rect({
      left: this.createX(0),
      top: this.createY(this.height - margins[2]),
      width: this.width,
      height: margins[2],
      lockMovementX: true,
      lockMovementY: true,
      selectable: false,
      hasControls: false,
    })
    this.margin.push(bottomMargin)
    //left
    const leftMargin = new fabric.Rect({
      left: this.createX(0),
      top: this.createY(0),
      width: margins[3],
      height: this.height,
      lockMovementX: true,
      lockMovementY: true,
      selectable: false,
      hasControls: false,
    })
    this.margin.push(leftMargin)
    this.margin.forEach(item => {
      // item.fill = "rgba(204,196,196,0.6)"
      item.fill = "transparent"
      this.canvas.add(item)
    })


    const pointerW = 25
    const pointerH = 14
    const offsetX = 10
    const offsetY = 10
    this.pointer.push(
      new fabric.Rect({
        left: this.createX(margins[3] - pointerW - offsetX),
        top: this.createY(margins[0] - pointerH - offsetY),
        width: pointerW,
        height: pointerH,
        fill: 'black',
        lockMovementX: true,
        lockMovementY: true,
        selectable: false,
        hasControls: false,
      })
    )

    this.pointer.push(
      new fabric.Rect({
        left: this.createX(margins[3] + this.contentW + offsetX),
        top: this.createY(margins[0] - pointerH - offsetY),
        width: pointerW,
        height: pointerH,
        fill: 'black',
        lockMovementX: true,
        lockMovementY: true,
        selectable: false,
        hasControls: false,
      })
    )
    this.pointer.push(
      new fabric.Rect({
        left: this.createX(margins[3] + this.contentW + offsetX),
        top: this.createY(margins[0] + this.contentH + offsetY),
        width: pointerW,
        height: pointerH,
        fill: 'black',
        lockMovementX: true,
        lockMovementY: true,
        selectable: false,
        hasControls: false,
      })
    )
    this.pointer.push(
      new fabric.Rect({
        left: this.createX(margins[3] - pointerW - offsetX),
        top: this.createY(margins[0] + this.contentH + offsetY),
        width: pointerW,
        height: pointerH,
        fill: 'black',
        lockMovementX: true,
        lockMovementY: true,
        selectable: false,
        hasControls: false,
      })
    )

    this.pointer.forEach(item => {
      this.canvas.add(item)
    })
  }



  createX(x) {
    return this.x + x
  }

  createY(y) {
    return this.y + y
  }


  createPoint(pointers) {

  }

}

class Sheet {
  static version = 1.0

  canvas = null

  pages = []

  maxPageSize = 4
  //t r b l
  margin = [75, 75, 75, 75]


  constructor(config) {
    const containerId = config.containerId
    const app = document.getElementById(containerId);
    let node = document.createElement("canvas");
    // const A4_WIDTH = 793.7;
    const A4_WIDTH = 793;
    const A4_HEIGHT = 1122;
    // const A4_HEIGHT = 1122.52;
    node.id = "sheet"
    node.width = A4_WIDTH;
    node.height = A4_HEIGHT * this.maxPageSize
    app.appendChild(node)
    this.pageW = A4_WIDTH
    this.pageH = A4_HEIGHT
    this.config = config
    this.canvas = new fabric.Canvas(node.id);
    this.canvas.setBackgroundColor("#fff");
    this.canvas.selection = false

    this.createEvent()
    // this.canvas.setBackgroundColor("rgba(227,33,33,0.3)")

    let page = this.addPage();

  }

  listFuns() {
    let allContent = this.allContent();
    return allContent.filter(item => {
      return item.item.data.data.callback != null
    }).map(item => {
      return {
        callback: item.item.data.data.callback.name,
        prams: item.item.data.data.params()
      }

    });
  }

  toPageImg() {

    const data = []
    for (let i = 0; i < this.pages.length; i++) {
      let page = this.pages[i];
      const res = this.canvas.toDataURL({
        format: 'jpeg',
        left: page.x,
        top: page.y,
        width: page.width,
        height: page.height,
        multiplier: 3,
      });
      data.push(res)

    }
    return data
  }

  toPdf() {
    let imgs = this.toPageImg();
    let pdf = new jsPDF('p', 'mm', 'a4') // A4纸，纵向
    var a4w = 210;
    var a4h = 297
    imgs.forEach((imageData, index) => {
      if (index !== 0) {
        pdf.addPage()
      }
      pdf.addImage(imageData, 'JPEG', 0, 0, a4w, a4h); // 添加图像到页面，保留10mm边距 [a4使用]
    })
    pdf.save("试卷" + '.pdf');

  }

  createEvent() {

  }


  rebuild() {
    let allContent1 = this.allContent();
    this.deletePage(0)
    this.addPage();
    allContent1.forEach((item, index) => {
      if (!item.item.data.data && !item.item.data.data.callback) {
        return
      }
      try {
        item.item.data.data.callback.apply(this, item.item.data.data.params());
      } catch (e) {
        console.log(item)
      }
    })
  }
  addPage() {
    let pageSize = this.pages.length;
    let page = new Page(this.canvas, [0, this.pageH * pageSize, this.pageW, this.pageH], pageSize + 1, this);
    if (pageSize + 1 === 1) {
      page.createHeadTitle();
      page.createInputRect()
      page.createTipContent();
      page.createCodeContent()

    }
    this.pages.push(page);
    this.pages.forEach(item => {
      item.createPageText()
    })
    return page
  }

  deletePage(current) {
    const clearList = []
    this.pages = this.pages.filter((item, index) => {
      let b = current > index;
      if (!b) {
        clearList.push(item)
      }
      return b;
    })
    clearList.forEach((item, index) => {
      item.clear()
    })

    this.pages.forEach((item, index) => {
      item.createPageText()
    })
  }

  appendContentTitle(title) {
    if (!this.pages[this.pages.length - 1].createContentTitle(title)) {
      this.addPage().createContentTitle(title)
    }
  }

  allContent() {
    const contentBodys = []
    for (let i = 0; i < this.pages.length; i++) {
      let page1 = this.pages[i];
      page1.contentManager.contentList.forEach(content => {
        contentBodys.push({
          page: page1,
          item: content
        })
      })
    }
    return contentBodys
  }

  removeContent(page, data) {
    this.reRender(page, data, true)
  }
  reRender(page, data, skill = false) {
    const current = page.page
    // page.contentManager.remove(data)

    const contentBodys = []

    page.contentManager.contentList.forEach((item, index) => {
      if (index >= data.items.index) {
        contentBodys.push({
          page: page,
          item: item
        })
      }
    })

    for (let i = current; i < this.pages.length; i++) {
      let page1 = this.pages[i];
      page1.contentManager.contentList.forEach(content => {
        contentBodys.push({
          page: page1,
          item: content
        })
      })
    }
    contentBodys.forEach(item => {
      item.page.contentManager.removeAndNextALl(item.item)
    })
    this.deletePage(current)
    contentBodys.forEach((item, index) => {
      if (index === 0 && skill) {
        return
      }
      try {
        item.item.data.data.callback.apply(this, item.item.data.data.params());
      } catch (e) {
        console.log(item)
      }
    })

  }

  appendTkSubjective(question) {
    let createSuccess = false

    if (!this.pages[this.pages.length - 1].createTk(question)) {
      this.addPage().createTk(question)
    }


  }

  appendQuestion(question) {
    if (!this.pages[this.pages.length - 1].createQuestions([question])) {
      this.addPage().createQuestions([question])
    }

  }


  consoleObjectiveQuestions() {
    const objectives = []
    for (let i = 0; i < this.pages.length; i++) {
      let items = {
        templateIndex: i,
        questionAreaItems: []
      };
      objectives.push(items)
      this.pages[i].contentManager.contentList.forEach(item => {
        if (item.data.data.type === 'questions') {
          let question = item.data.data.questions[0];
          items.questionAreaItems.push({
            questionId: question.questionId,
            questionIndex: question.questionIndex,
            positions: question.positions.map(p => {
              return {
                value: p.value,
                position: p.position()
              }
            })
          })
        }
      })
    }

    return objectives
  }

  consoleSubjectiveQuestions() {

    let allContent1 = this.allContent();
    return allContent1.filter(item => {
      return item.item.data && item.item.data.data && item.item.data.data.isSubjective
    })
  }

  consoleSheetConfig(rate = 1) {

    let pointers = this.pages.map(item => {
      return {
        page: item.page - 1,
        position: item.pointer
      }
    });
    const pointerArea = pointers.map(item => {
      return {
        pointers: item.position.map(pointer => {
          return {
            position: [pointer.left, pointer.top - (item.page * this.pageH), pointer.width, pointer.height]
          }
        })
      }
    })

    let studentIdArea = this.pages[0].codes.map(item => {
      return item()
    });

    const objectQuestions = this.consoleObjectiveQuestions()
    let subjectiveQuestions = this.consoleSubjectiveQuestions().map(item => {
      return {
        questionId: item.item.data.data.question.questionId,
        questionIndex: item.item.data.data.question.questionIndex,
        templateIndex: item.page.page - 1,
        positions: [{
          value: 'content',
          position: item.item.data.data.getPositions()
        }],
      }
    });

    let newVar = {
      studentIdArea: studentIdArea,
      subjectiveArea: subjectiveQuestions,
      objectiveArea: objectQuestions,
      pointerArea: pointerArea,
    };
    objectQuestions.forEach(objectiveArea => {
      objectiveArea.questionAreaItems.forEach(area => {
        area.positions = area.positions.map(position => {
          position.position[1] = position.position[1] - (objectiveArea.templateIndex * this.pageH)
          position.position = position.position.map(p => {
            return p * rate
          })
          return position
        })
      })
    })
    pointerArea.forEach((page, pageIndex) => {
      page.pointers = page.pointers.map(pointer => {
        pointer[1] = pointer[1] - (pageIndex * this.pageH)
        return {
          position: pointer.position.map(item => item * rate)
        }
      })
    })
    studentIdArea.forEach(code => {
      code.container = code.container.map(item => item * rate)
      code.positions = code.positions.map(item => {
        item.position = item.position.map(p => p * rate)
        return item
      })
    })
    subjectiveQuestions.forEach(sub => {
      sub.positions = sub.positions.map(p => {
        p.position[1] = p.position[1] - (sub.templateIndex * this.pageH)
        p.position = p.position.map(p1 => p1 * rate)
        return p
      })
    })
    return newVar
  }
  consolePointer() {
    return this.pages.map(item => {
      return {
        page: item,
        pointer: item.pointer
      }
    })
  }



  appendKb(question, first = false, controller = false) {

    const {
      questionId,
      questionIndex,
      baseType,
      paperIndex,
      sourceHeight,
      height
    } = question


    this.pages.length

    let page = this.pages[this.pages.length - 1];
    let freeHeight = page.getFreeHeight();
    if (freeHeight >= 30 && freeHeight >= height) {
      page.createKb(question, first ? height : null, first ? true : controller)
      return true
    }
    const otherH = Math.max(height - freeHeight, 60)

    if (freeHeight < 30) {
      page = this.addPage()
      this.appendKb(question, first)
      // this.appendKb({...question, height: freeHeight}, first);

      // this.addPage()

    } else {
      this.appendKb({...question, height: freeHeight}, first);
      this.addPage()
      this.appendKb({...question, height: otherH}, false, true)

    }


    return false
  }
}

export default Sheet
